{-# LANGUAGE DeriveFunctor #-}

import Control.Monad
import Data.Functor.Identity

-- data Maybe a = Nothing | Just a
data MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)} deriving (Functor)

instance (Monad m) => Applicative (MaybeT m) where
  pure :: Monad m => a -> MaybeT m a
  pure x = MaybeT $ return (Just x)
  (<*>) :: Monad m => MaybeT m (a -> b) -> MaybeT m a -> MaybeT m b
  (<*>) = ap

instance (Monad m) => Monad (MaybeT m) where
  (>>=) :: (Monad m) => MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b
  MaybeT a >>= f =
    MaybeT $ do
      result <- a
      case result of
        Nothing -> return Nothing
        Just x -> runMaybeT (f x)
